﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Linq;
using System.ComponentModel;
using MyQQListView.Enum;
using Lyh.MyQQListView.Properties;
using Lyh.MyQQListView.Enum;
using Lyh.MyQQListView.Util;

namespace MyQQListView
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(QQListView), "Resources.label")]
    public partial class QQListView : UserControl
    {
        #region --私有变量--

        private int groupCount = 0;
        private int groupID = 50;
        private int offset = 4;
        private int groupControlHeight = 24;
        private int friendControlHeight = 56;

        private Friend selectedFriend = null;
        private Friend oldSelectedFriend = null;
        private GroupControl selectedGroup = null;
        private Thread skinThread = null;
        private IList<Group> groupList = null;

        private bool isTransparent = false;
        private QQContextMenu panelContextMenuScript = null;
        private QQContextMenu groupContextMenuScript = null;
        private QQContextMenu friendContextMenuScript = null;

        private HeadImageMode headImageMode=HeadImageMode.Normal;

        #endregion

        #region --定义委托--

        public delegate void SelectedFriendChangedEventHandler(object sender, EventArgs e);
        [Category("鼠标事件")]
        [Description("选择好友时发生")]
        public event SelectedFriendChangedEventHandler SelectedFriendChanged;

        public delegate void FriendMouseDoubleClickEventHandler(object sender, EventArgs e);
        [Category("鼠标事件")]
        [Description("双击好友时发生")]
        public event FriendMouseDoubleClickEventHandler FriendMouseDoubleClick;

        public delegate void GroupExpandChangedEventHandler(Group sender, bool Currentstate);
        [Category("鼠标事件")]
        [Description("单击分组时发生")]
        public event GroupExpandChangedEventHandler GroupExpandChanged;

        public delegate void ShowFriendContextMenuEventHandler(FriendControl sender, MouseEventArgs e);
        [Category("鼠标事件")]
        [Description("显示好友右键菜单时发生")]
        public event ShowFriendContextMenuEventHandler ShowFriendContextMenu;

        public delegate void ShowGroupContextMenuEventHandler(GroupControl sender, MouseEventArgs e);
        [Category("鼠标事件")]
        [Description("显示分组右键菜单时发生")]
        public event ShowGroupContextMenuEventHandler ShowGroupContextMenu;

        
        #endregion

        #region --公共变量--

        [Category("右键菜单")]
        [Description("设置或获取面板的右键菜单")]
        public QQContextMenu PanelContextMenuScript
        {
            get { return panelContextMenuScript; }
            set { panelContextMenuScript = value; }
        }

        [Category("右键菜单")]
        [Description("设置或获取分组的右键菜单")]
        public QQContextMenu GroupContextMenuScript
        {
            get { return groupContextMenuScript; }
            set { groupContextMenuScript = value; }
        }

        [Category("右键菜单")]
        [Description("设置或获取好友的右键菜单")]
        public QQContextMenu FriendContextMenuScript
        {
            get { return friendContextMenuScript; }
            set { friendContextMenuScript = value; }
        }

        [Category("外观")]
        [Description("设置或获取控件是否透明")]
        [DefaultValue(false)]
        public bool IsTransparent
        {
            get
            {
                return isTransparent;
            }
            set
            {
                isTransparent = value;
                if (isTransparent)
                    this.BackColor = Color.Transparent;
                else
                    this.BackColor = Color.White;
                skinThread = new Thread(new ParameterizedThreadStart(ChangeSkin));
                skinThread.Start(this.BackColor);
            }
        }

        [Category("数据")]
        [Description("设置或获取之前选择的好友")]
        [Browsable(false)]
        public Friend OldSelectedFriend
        {
            get
            {
                return oldSelectedFriend;
            }
            set
            {
                oldSelectedFriend = value;
            }
        }

        [Category("数据")]
        [Description("设置或获取当前选择的好友")]
        [Browsable(false)]
        public Friend SelectedFriend
        {
            get
            {
                return selectedFriend;
            }
            set
            {
                if (selectedFriend != null)
                    OldSelectedFriend = selectedFriend;
                selectedFriend = value;
                UpdateFriendControl();
            }
        }

        [Category("数据")]
        [Description("设置或获取当前选择的分组")]
        [Browsable(false)]
        public GroupControl SelectedGroup
        {
            get
            {
                return selectedGroup;
            }
            set
            {
                selectedGroup = value;
            }
        }

        [Category("数据")]
        [Description("头像大小")]
        [Browsable(true)]
        public HeadImageMode HeadImageMode
        {
            get { return headImageMode; }
            set { headImageMode = value; }
        }

        [Category("数据")]
        [Description("控件之间的偏移量")]
        [Browsable(false)]
        public int Offset
        {
            get { return offset; }
        }

        [Category("数据")]
        [Description("分组高度")]
        [Browsable(false)]
        public int GroupControlHeight
        {
            get
            {
                return groupControlHeight;
            }
        }

        [Category("数据")]
        [Description("好友高度")]
        [Browsable(false)]
        public int FriendControlHeight
        {
            get
            {
                friendControlHeight = (int)headImageMode + offset * 4;
                return friendControlHeight;
            }
        }

        #endregion

        public QQListView()
        {
            this.AutoScroll = true;
            this.BackColor = Color.White;
            this.ForeColor = Color.Black;
            this.Name = "ListView";
            //this.Size = new Size(235, 350);

            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);

            groupList = new List<Group>(5);
        }

        /// <summary>
        /// 清空所有控件
        /// </summary>
        public void Clear()
        {
            this.Controls.Clear();
        }

        public void SelectFriend(int uin)
        {
            (Controls["friend_" + uin] as FriendControl).Selected();
        }

        public void GetFriendInfo(int uin)
        {

        }

        public void InitFriendList(IList<Group> groups)
        {
            //每个好友Panel的高度
            int friendPanelHeight = (int)HeadImageMode + 4 * offset;
            //分组个数
            groupCount = groups.Count;
            //最近一个分组的位置高度增量
            int lastGroupHeight = 0;
            for (int i = 0; i < groupCount; i++)
            {
                GroupControl cGroup = new GroupControl();
                this.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Left) | AnchorStyles.Right)));
                cGroup.Location = new Point(1, groupControlHeight * i + i + 1 + lastGroupHeight);
                cGroup.Name = "group_" + groups[i].Id;
                cGroup.Size = new Size(Width, groupControlHeight);
                cGroup.GroupInfo = groups[i];
                cGroup.ExpandChanged += new GroupControl.ExpandChangeEventHandler(cGroup_ExpandChanged);
                cGroup.ShowContextMenu += new GroupControl.ShowContextMenuEventHandler(cGroup_ShowContextMenu);
                this.Controls.Add(cGroup);
                int friendCount = groups[i].FriendCount;
                Panel panel = new Panel();
                panel.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Left) | AnchorStyles.Right)));
                panel.BackColor = this.BackColor;
                panel.Location = new Point(0, 0);
                panel.Name = "userPanel_" + groups[i].Id;
                panel.Size = new Size(this.Width, friendCount * friendPanelHeight);
                panel.Visible = false;
                if (friendCount > 0)
                {
                    for (int j = 0; j < friendCount; j++)
                    {
                        Friend friendInfo = (Friend)groups[i].Friends[j];
                        if (friendInfo.UserState != UserState.Offline && friendInfo.UserState != UserState.Invisible)
                        {
                            cGroup.GroupInfo.OnlineFriendCount++;
                        }
                        friendInfo.GroupID = groups[i].Id;
                        FriendControl friend = new FriendControl();
                        friend.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Left) | AnchorStyles.Right)));
                        friend.BackColor = this.BackColor;
                        friend.HeadImageMode = HeadImageMode;
                        friend.Location = new Point(1, friendPanelHeight * j);
                        friend.Name = "friend_" + friendInfo.Uin;
                        friend.Size = new Size(panel.Width - 2, friendPanelHeight - 1);
                        friend.Friend = friendInfo;
                        friend.Selecting += new FriendControl.SelectedEventHandler(friend_SelectedFriendChanged);
                        friend.ShowContextMenu += new FriendControl.ShowContextMenuEventHandler(friend_ShowContextMenu);
                        friend.MouseDoubleClick += new MouseEventHandler(friend_MouseDoubleClick);
                        panel.Controls.Add(friend);
                    }
                }
                this.Controls.Add(panel);

                Group gp = groupList.FirstOrDefault(g => g.Id == groups[i].Id);
                if (gp != null && gp.IsExpanded)
                {
                    lastGroupHeight += gp.FriendCount * friendPanelHeight;
                    MouseHelper.AutoClick(cGroup);
                }
                else
                    groupList.Add(groups[i]);

            }
            GC.Collect();
        }

        #region --操作好友事件--

        private void friend_ShowContextMenu(FriendControl sender, MouseEventArgs e)
        {
            if (friendContextMenuScript != null)
                friendContextMenuScript.Show(sender, e.Location);
            if (ShowFriendContextMenu != null)
                ShowFriendContextMenu(sender, e);
        }

        private void friend_SelectedFriendChanged(Friend sender)
        {
            SelectedFriend = sender;
            if (SelectedFriendChanged != null)
                SelectedFriendChanged(sender, new EventArgs());
        }

        private void friend_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (FriendMouseDoubleClick != null)
                FriendMouseDoubleClick(sender, e);
        }

        #endregion

        public int AddGroup()
        {
            UpdateLayout(2, 0);

            groupID += 1;
            Group group = new Group();
            group.OnlineFriendCount = 0;
            group.Title = "";
            group.Id = groupID;
            group.Friends = new List<Friend>();
            group.UserOrder = UserOrder.NickName;
            groupList.Add(group);
            GroupControl cGroup = new GroupControl();
            this.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Left) | AnchorStyles.Right)));
            this.BackColor = this.BackColor;
            cGroup.Location = new Point(2, 1);
            cGroup.Name = "group_" + group.Id;
            cGroup.Size = new Size(Width, 24);
            cGroup.GroupInfo = group;
            cGroup.ExpandChanged += new GroupControl.ExpandChangeEventHandler(cGroup_ExpandChanged);
            cGroup.ShowContextMenu += new GroupControl.ShowContextMenuEventHandler(cGroup_ShowContextMenu);
            this.Controls.Add(cGroup);

            Panel panel = new Panel();
            panel.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Left) | AnchorStyles.Right)));
            panel.BackColor = this.BackColor;
            panel.Location = new Point(0, 0);
            panel.Name = "userPanel_" + group.Id;
            panel.Size = new Size(this.Width, group.FriendCount * 56);
            panel.Visible = false;
            this.Controls.Add(panel);
            return groupID;
        }

        public int AddGroup(string groupName)
        {
            groupID += 1;
            Group group = new Group();
            group.OnlineFriendCount = 0;
            group.Title = groupName;
            group.Id = groupID;
            groupList.Add(group);
            return groupID;
        }

        public void ExpandGroup(int groupID)
        {
            GroupControl gg = Controls["group_" + groupID] as GroupControl;
            if (!gg.IsExpand)
            {
                gg.IsExpand = true;
                ShowFriendsList(groupID);
            }
        }

        public void CollapseGroup(int groupID)
        {
            GroupControl gg = Controls["group_" + groupID] as GroupControl;
            if (gg.IsExpand)
            {
                gg.IsExpand = false;
                HideFriendsList(groupID);
            }
        }

        public void DeleteGroup(int gid)
        {
            Controls["group_" + gid].Visible = false;
            Controls["userPanel_" + gid].Visible = false;
            Controls["group_" + gid].Top -= 25;
            groupCount--;
            UpdateLayout(0, gid);
            groupList.Remove((Controls["group_" + gid] as GroupControl).GroupInfo);
            Controls["group_" + gid].Dispose();
            Controls["userPanel_" + gid].Dispose();
            Controls.RemoveByKey("group_" + gid);
            Controls.RemoveByKey("userPanel_" + gid);
            if (SelectedFriend != null)
            {
                if (SelectedFriend.GroupID == gid)
                    OldSelectedFriend = SelectedFriend = null;
            }
        }

        private void cGroup_ShowContextMenu(GroupControl sender, MouseEventArgs e)
        {
            SelectedGroup = sender;
            if (groupContextMenuScript != null)
                groupContextMenuScript.Show(sender, e.Location);
            if (ShowGroupContextMenu != null)
                ShowGroupContextMenu(sender, e);
        }

        private void cGroup_ExpandChanged(Group sender, bool Currentstate)
        {
            groupList.First(g => g.Id == sender.Id).IsExpanded = Currentstate;
            if (Currentstate)
                ShowFriendsList(sender.Id);
            else
                HideFriendsList(sender.Id);
            if (GroupExpandChanged != null)
                GroupExpandChanged(sender, Currentstate);
        }

        private void ChangeSkin(object obj)
        {
            Color color = (Color)obj;
            for (int i = 0; i < Controls.Count; i++)
            {
                if (Controls[i].Name.IndexOf("userPanel") != -1)
                {
                    Controls[i].BackColor = color;
                    for (int j = 0; j < Controls[i].Controls.Count; j++)
                    {
                        Controls[i].Controls[j].BackColor = color;
                    }
                }
            }
        }

        private void UpdateFriendControl()
        {
            if (OldSelectedFriend != null)
            {
                Panel p = (Panel)Controls["userPanel_" + OldSelectedFriend.GroupID];
                if (p != null)
                {
                    FriendControl fc = p.Controls["friend_" + OldSelectedFriend.Uin] as FriendControl;
                    fc.IsSelected = false;
                }
            }
        }
        
        private void ShowFriendsList(int gid)
        {
            if (gid >= 0)
            {
                this.Controls["userPanel_" + gid].Top = this.Controls["group_" + gid].Top + 23;
                this.Controls["userPanel_" + gid].Show();
                UpdateLayout(1, gid);
            }
        }

        private void HideFriendsList(int gid)
        {
            if (gid >= 0)
            {
                this.Controls["userPanel_" + gid].Hide();
                UpdateLayout(1, gid);
                if (SelectedFriend != null)
                {
                    if (SelectedFriend.GroupID == gid)
                        OldSelectedFriend = SelectedFriend = null;
                }
                GC.Collect();
            }
        }

        private void UpdateLayout(int action, int gid)
        {
            if (action == 0)
            {
                int cid = Controls.IndexOfKey("group_" + gid);
                for (int i = cid + 2; i < Controls.Count; i += 2)
                {
                    if (this.Controls[i - 1].Visible)
                    {
                        this.Controls[i].Top = this.Controls[i - 2].Top + this.Controls[i - 1].Height;
                        this.Controls[i + 1].Top = this.Controls[i].Top + 25;
                    }
                    else
                    {
                        this.Controls[i].Top = this.Controls[i - 2].Top + 25;
                        this.Controls[i + 1].Top = this.Controls[i].Top + 25;
                    }
                }
            }
            else if (action == 1)
            {
                int cid = Controls.IndexOfKey("group_" + gid);
                for (int i = cid + 2; i < Controls.Count; i += 2)
                {
                    if (Controls[i - 1].Visible)
                    {
                        Controls[i].Top = Controls[i - 2].Top + Controls[i - 1].Height + 25;
                        Controls[i + 1].Top = Controls[i].Top + 25;
                    }
                    else
                    {
                        Controls[i].Top = Controls[i - 2].Top + 25;
                        Controls[i + 1].Top = Controls[i].Top + 25;
                    }
                }
            }
            else if (action == 2)
            {
                for (int i = 0; i < Controls.Count; i += 2)
                {
                    Controls[i].Top += 25;
                    Controls[i + 1].Top += 25;
                }
            }
            else if (action == 3)
            {
                for (int i = 0; i < groupList.Count; i++)
                {
                    if (i == 0)
                    {
                        Controls[i].Top = 1;
                        Controls[i + 1].Top = Controls[i].Top + 25;
                    }
                    else
                    {
                        Group gg = groupList[i - 1] as Group;
                        Group ggg = groupList[i] as Group;
                        if (Controls["userPanel_" + gg.Id].Visible)
                        {
                            Controls["group_" + ggg.Id].Top = Controls["group_" + gg.Id].Top + Controls["userPanel_" + gg.Id].Height + 25;
                            Controls["userPanel_" + ggg.Id].Top = Controls["group_" + ggg.Id].Top + 25;
                        }
                        else
                        {
                            Controls["group_" + ggg.Id].Top = Controls["group_" + gg.Id].Top + 25;
                            Controls["userPanel_" + ggg.Id].Top = Controls["group_" + ggg.Id].Top + 25;
                        }
                    }
                }
            }
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            GC.Collect();
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                default:
                    break;
            }
            base.WndProc(ref m);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            if (SelectedGroup != null)
                SelectedGroup.Focus();
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // QQListView
            // 
            this.BackColor = System.Drawing.SystemColors.Control;
            this.Name = "QQListView";
            this.Size = new System.Drawing.Size(50, 100);
            this.ResumeLayout(false);

        }
    }
}
